# This is a sample Python script.
# Press Shift+F10 to execute it or replace it with your code.
# Press Double Shift to search everywhere for classes, files, tool windows, actions, and settings.

# See PyCharm help at https://www.jetbrains.com/help/pycharm/
# read 方法
# print(master.execute(35,cst.READ_HOLDING_REGISTERS,102,10))#slaveAddr funCode startAddr regNum
# write方法
# print(master.execute(35, cst.WRITE_MULTIPLE_REGISTERS, 9, output_value=[1]))

# 导入mudoel模块
from MainWindows import Ui_MainWindow
from ScopeWindows import Ui_Form
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
import serial
from serial.tools import list_ports
import sys
from QCustomPlot_PyQt5 import *
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
from PyQt5.QtGui import *

class chart(object):
    def __init__(self):
        self.line = []
        self.pointX = []
        self.pointY = []


class Ui_Scope(Ui_Form):
    def __init__(self):
        super(Ui_Form, self).__init__()
        self.Form = QtWidgets.QWidget()
        self.Form.closeEvent = self.closed
        self.setupUi(self.Form)
        self.chartchannel = [chart()] * 8
        self.Revdata = []
        for i in range(8):
            self.chartchannel[i] = self.CreatLine(i)
        self.showEn = True

    def closed(self, a0: QtGui.QCloseEvent) -> None:
        self.showEn = False
        del self.chartchannel
        del self.Revdata

#   控件关联函数设置
    def DealConnet(self):
        self.clearButton.clicked.connect(self.clear)
        self.checkBox1.clicked.connect(self.LineShowEn)
        self.checkBox2.clicked.connect(self.LineShowEn)
        self.checkBox3.clicked.connect(self.LineShowEn)
        self.checkBox4.clicked.connect(self.LineShowEn)
        self.checkBox5.clicked.connect(self.LineShowEn)
        self.checkBox6.clicked.connect(self.LineShowEn)
        self.checkBox7.clicked.connect(self.LineShowEn)
        self.checkBox8.clicked.connect(self.LineShowEn)
        self.outputButton.clicked.connect(self.exportData)
        self.InputButton.clicked.connect(self.importData)

#   处理接收到的数据
    def DealData(self, data):
        for i in range(self.ChannelNum.value()):
            self.chartchannel[i].pointY.append(data[i])
            if len(self.chartchannel[i].pointX) == 0:
                self.chartchannel[i].pointX.append(0)
            else:
                self.chartchannel[i].pointX.append(self.chartchannel[i].pointX[-1] + 1)
            self.set(i)
        if self.AutoButton.isChecked():
            self.qchartView.xAxis.setRange(self.chartchannel[0].pointX[-1] - 10,
                                           self.chartchannel[0].pointX[-1] + 10)
        else:
            self.qchartView.rescaleAxes()
        # 必须调用图像刷新
        self.qchartView.replot()
        pass

#   运行时不可以设置参数
    def runState(self, state):
        if state == True:
            self.ChannelNum.setEnabled(False)
            self.slave_ID.setEnabled(False)
            self.slave_Address.setEnabled(False)
        else:
            self.ChannelNum.setEnabled(True)
            self.slave_ID.setEnabled(True)
            self.slave_Address.setEnabled(True)

#   导入数据
    def importData(self):
        self.file_name = QFileDialog.getOpenFileName(self.Form, '导入文件', ' ', 'TXT files(*.txt)')
        try:
            with open(self.file_name[0], "r") as self.RevFile:
                self.ChannelNum.value = int(self.RevFile.readline())
                self.slave_ID.setText(str(int(self.RevFile.readline())))
                self.slave_Address.setText(str(int(self.RevFile.readline())))
                self.clear()
                for i in range(self.ChannelNum.value):
                    tmplist = self.RevFile.readline()
                    if tmplist != '\n':
                        tmplist = tmplist.split('[')[1]
                        tmplist = tmplist.split(']\n')[0]
                        tmplist = tmplist.split(', ')
                        self.chartchannel[i].pointX = [int(x) for x in tmplist]
                    tmplist = self.RevFile.readline()
                    if tmplist != '\n':
                        tmplist = tmplist.split('[')[1]
                        tmplist = tmplist.split(']\n')[0]
                        tmplist = tmplist.split(', ')
                        self.chartchannel[i].pointY = [int(x) for x in tmplist]
                    self.set(i)
                self.qchartView.replot()
        except:
            pass

#   导出数据
    def exportData(self):
        self.file_name = QFileDialog.getSaveFileName(self.Form, '导出文件', ' ', 'TXT files(*.txt)')
        try:
            with open(self.file_name[0], "w+") as self.RevFile:
                self.a = [1, 2, 3]
                self.RevFile.write(str(self.ChannelNum.value()))
                self.RevFile.write('\n')
                self.RevFile.write(self.slave_ID.text())
                self.RevFile.write('\n')
                self.RevFile.write(self.slave_Address.text())
                self.RevFile.write('\n')
                for i in range(self.ChannelNum.value()):
                    if len(self.chartchannel[i].pointX) != 0:
                        self.RevFile.write(str(self.chartchannel[i].pointX))
                    self.RevFile.write('\n')
                    if len(self.chartchannel[i].pointY) != 0:
                        self.RevFile.write(str(self.chartchannel[i].pointY))
                    self.RevFile.write('\n')
        except:
            pass

#   清屏
    def clear(self):
        for i in range(8):
            self.chartchannel[i].pointX.clear()
            self.chartchannel[i].pointY.clear()
            self.set(i)
        self.qchartView.replot()

#   设置曲线的坐标数据
    def set(self, channelNo):
        self.chartchannel[channelNo].line.setData(self.chartchannel[channelNo].pointX, self.chartchannel[channelNo].pointY)

#   显示
    def show(self):
        self.DealConnet()
        self.Init()
        self.Form.show()

#   初始化
    def Init(self):
        self.clear()
        # 自动设置坐标轴范围及刻度
        self.qchartView.rescaleAxes()
        # 添加一些交互功能，拖拽图像，缩放，选择曲线
        self.qchartView.setInteractions(QCP.Interactions(QCP.iRangeDrag | QCP.iRangeZoom | QCP.iSelectPlottables))

#   创建曲线
    def CreatLine(self, channelNo):
        tmp = chart()
        tmp.line = self.qchartView.addGraph()
        tmp.pointX = []
        tmp.pointY = []
        if channelNo == 0:
            tmp.line.setPen(QPen(QColor(255, 0, 0)))
        elif channelNo == 1:
            tmp.line.setPen(QPen(QColor(0, 0, 255)))
        elif channelNo == 2:
            tmp.line.setPen(QPen(QColor(170, 170, 0)))
        elif channelNo == 3:
            tmp.line.setPen(QPen(QColor(0, 170, 0)))
        elif channelNo == 4:
            tmp.line.setPen(QPen(QColor(255, 0, 255)))
        elif channelNo == 5:
            tmp.line.setPen(QPen(QColor(255, 170, 255)))
        elif channelNo == 6:
            tmp.line.setPen(QPen(QColor(170, 255, 0)))
        elif channelNo == 7:
            tmp.line.setPen(QPen(QColor(255, 170, 0)))
        return tmp

#   曲线显示使能处理
    def LineShowEn(self):
        if self.checkBox1.isChecked():
            self.chartchannel[0].line.setVisible(True)
        else:
            self.chartchannel[0].line.setVisible(False)

        if self.checkBox2.isChecked():
            self.chartchannel[1].line.setVisible(True)
        else:
            self.chartchannel[1].line.setVisible(False)

        if self.checkBox3.isChecked():
            self.chartchannel[2].line.setVisible(True)
        else:
            self.chartchannel[2].line.setVisible(False)

        if self.checkBox4.isChecked():
            self.chartchannel[3].line.setVisible(True)
        else:
            self.chartchannel[3].line.setVisible(False)

        if self.checkBox5.isChecked():
            self.chartchannel[4].line.setVisible(True)
        else:
            self.chartchannel[4].line.setVisible(False)

        if self.checkBox6.isChecked():
            self.chartchannel[5].line.setVisible(True)
        else:
            self.chartchannel[5].line.setVisible(False)

        if self.checkBox7.isChecked():
            self.chartchannel[6].line.setVisible(True)
        else:
            self.chartchannel[6].line.setVisible(False)

        if self.checkBox8.isChecked():
            self.chartchannel[7].line.setVisible(True)
        else:
            self.chartchannel[7].line.setVisible(False)


class serialmain(Ui_MainWindow):
    def __init__(self):
        super(Ui_MainWindow, self).__init__()
        self.scope_num = 0
        self.scope = []
        self.scope_cnt = 0

    #设置控件连接
    def CortrolConnect(self):
        # 开串口按键
        self.StartButton.clicked.connect(self.App_openserial)
        # 定时器链接
        self.sendtimer.timeout.connect(self.APP_SendData)
        # 新建窗口
        self.newButton.clicked.connect(self.APP_creatNew)
        # 视图调整
        self.viewButton.clicked.connect(self.APP_ViewAdjust)

    def APP_ChartInitDisply(self):
        self.APP_creatNew()

    # 初始化串口
    def Init_GetSerialComPort(self):
        self.sendtimer = QtCore.QTimer()
        self.App_openserial_fg = False
        self.APP_ChartInitDisply()
        # 获取可用串口号
        ports_list = list(serial.tools.list_ports.comports())
        if len(ports_list) <= 0:
            pass
        else:
            for comport in ports_list:
                self.comboBox_1.addItem(list(comport)[0], comport)
        # 获取波特率
        for comport in range(len(serial.SerialBase.BAUDRATES)):
            self.comboBox_2.addItem(str(serial.SerialBase.BAUDRATES[comport]), comport)
        # 获取数据位
        for comport in range(len(serial.SerialBase.BYTESIZES)):
            self.comboBox_3.addItem(str(serial.SerialBase.BYTESIZES[comport]), comport)
        # 获取校验位
        for comport in range(len(serial.SerialBase.PARITIES)):
            self.comboBox_4.addItem(str(serial.SerialBase.PARITIES[comport]), comport)
        # 获取停止位
        for comport in range(len(serial.SerialBase.STOPBITS)):
            self.comboBox_5.addItem(str(serial.SerialBase.STOPBITS[comport]), comport)

        self.comboBox_1.setCurrentText("COM2")
        self.comboBox_2.setCurrentText("9600")
        self.comboBox_3.setCurrentText("8")
        self.comboBox_4.setCurrentText("N")
        self.comboBox_5.setCurrentText("1")

    # 配置好参数，打开串口,按下打开串口，松开则关闭串口，故障则恢复
    def App_openserial(self):
        try:
            if self.StartButton.isChecked():
                self.master = modbus_rtu.RtuMaster(serial.Serial(port=self.comboBox_1.currentText(),
                                                            baudrate=int(self.comboBox_2.currentText()),
                                                            bytesize=int(self.comboBox_3.currentText()),
                                                            parity=self.comboBox_4.currentText(),
                                                            stopbits=serial.SerialBase.STOPBITS[self.comboBox_5.currentIndex()],
                                                            timeout=1))
                self.master.set_timeout(5)
                self.master.set_verbose(True)
                #启动定时器
                self.sendtimer.start(10)
                self.StartButton.setText("关闭串口")
            else:
                self.sendtimer.stop()
                self.master._do_close()
                self.StartButton.setText("打开串口")
        except:
            self.StartButton.setChecked(False)
            self.sendtimer.stop()
            self.StartButton.setText("打开串口")
            self.statusBar.showMessage("串口打开失败", 3000)

    # 新建窗口
    def APP_creatNew(self):
        self.scope_num += 1
        if len(self.scope) != 0:
            for i in range(len(self.scope)):
                if self.scope[i].showEn == False:
                    self.scope[i] = Ui_Scope()
                    self.scope[i].Form.setWindowTitle("波形图" + str(self.scope_num))
                    self.mdiArea.addSubWindow(self.scope[i].Form)
                    self.scope[i].show()
                    return
        self.scope.append(Ui_Scope())
        self.scope[-1].Form.setWindowTitle("波形图"+str(self.scope_num))
        self.mdiArea.addSubWindow(self.scope[-1].Form)
        self.scope[-1].show()

    # 发送数据
    def APP_SendData(self):
        self.sendtimer.stop()
        try:
            for i in range(self.scope_cnt, len(self.scope)):
                if self.scope[i].showEn != False:
                    self.scope[i].Revdata = list(self.master.execute(int(self.scope[i].slave_ID.text()), cst.READ_HOLDING_REGISTERS,
                                                 int(self.scope[i].slave_Address.text()), int(self.scope[i].ChannelNum.value())))
                    self.scope[i].DealData(self.scope[i].Revdata)
                    self.scope_cnt = i+1
                    if self.scope_cnt >= len(self.scope):
                        self.scope_cnt = 0
                    break
            self.sendtimer.start(10)
        except:
            self.StartButton.setChecked(False)
            self.StartButton.setText("打开串口")
            self.master._do_close()
            self.statusBar.showMessage("通讯超时", 3000)

    # 视图调整
    def APP_ViewAdjust(self):
        self.mdiArea.tileSubWindows()


#主函数
if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    app.setStyle('fusion')
    MainWindow = QtWidgets.QMainWindow()
    ui = serialmain()
    ui.setupUi(MainWindow)
    # 启动程序时先获取串口号
    ui.Init_GetSerialComPort()
    ui.CortrolConnect()
    MainWindow.show()
    sys.exit(app.exec_())